package org.goyo.main.domain.dao;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.goyo.common.baseBean.Constants;
import org.goyo.common.utils.DateUtils;
import org.goyo.common.utils.Pager;
import org.goyo.main.domain.entity.BaseObject;
import org.goyo.main.domain.entity.system.SysUser;
import org.goyo.main.web.controller.system.SessionUtil;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.util.Assert;

/**
 * 基本DAO
 * @author chenchuan
 *
 */
public class BaseDAO implements IBaseDAO{
  
  
/*      @PersistenceContext  
      private EntityManager entityManager;  
        
      @Override  
      public EntityManager getEntityManager(){  
          return this.entityManager;  
      }  */


	@Resource
	private SessionFactory sessionFactory;
	
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public Session getSession() {
		// 事务必须是开启的(Required)，否则获取不到
		return sessionFactory.getCurrentSession();
	}

	public <T> T get(Class<T> entityClass,Serializable pk) {
		Assert.notNull(pk, "pk is required");
		return (T) getSession().get(entityClass, pk);
	}

	public <T> T load(Class<T> entityClass,Serializable pk) {
		Assert.notNull(pk, "pk is required");
		return (T) getSession().load(entityClass, pk);
	}

	public <T> List<T> getAll(Class<T> entityClass) {
		ClassMetadata classMetadata = getSessionFactory().getClassMetadata(entityClass);
		String hql = "from " + classMetadata.getEntityName();
		return getSession().createQuery(hql).list();
	}

	public <T> Long getTotalCount(Class<T> entityClass) {
		ClassMetadata classMetadata = getSessionFactory().getClassMetadata(entityClass);
		final String hql = "select count(*) from " + classMetadata.getEntityName();
		return (Long) getSession().createQuery(hql).uniqueResult();
	}

	public <T> T save(Object entity) {
		Assert.notNull(entity, "entity is required");
		return (T) getSession().save(entity);
	}
	
	public void saveOrUpdate(Object entity) {
		Assert.notNull(entity, "entity is required");
		getSession().saveOrUpdate(entity);
	}

	public void update(Object entity) {
		Assert.notNull(entity, "entity is required");
		getSession().update(entity);
	}

	public void delete(Object entity) {
		Assert.notNull(entity, "entity is required");
		getSession().delete(entity);
	}

	public <T> T findUnique(String hql,Object... params){
		Query query = getSession().createQuery(hql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		List<T> list = query.list();
		if(list.isEmpty()){
			return null;
		}
		if(list.size() > 1){
			throw new RuntimeException("result not unique!");
		}
		return list.get(0);
	}

	/**
	 * 分页器
	 * @param hql
	 * @param params
	 * @param <T>
	 * @return
	 */
//	@Deprecated
	public <T> List<T> findObjects(String hql,Pager page,Object... params) {
		Query query = getSession().createQuery(hql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		if(null!=page){
			query.setFirstResult(page.getCurrPage() *page.getPageSize() - page.getPageSize());
			query.setMaxResults(page.getPageSize());
		}
		List<T> list = query.list();
		return list;
	}
	
	/**
	 * 分页查询 返回page对象
	 * @param hql
	 * @param page
	 * @param params
	 * @return
	 */
	public Pager findObjectsByPager(String hql,String countHql,Pager page,Object... params){
      Query query = getSession().createQuery(hql);
      if (params != null) {
        for (int i = 0; i < params.length; i++) {
            query.setParameter(i, params[i]);
        }
    }
      query.setFirstResult(page.getCurrPage() *page.getPageSize() - page.getPageSize());
      query.setMaxResults(page.getPageSize());
      page.setList(query.list());
      page.setCount(getTotalByCond(countHql,params));
      return page;
	}
	
	
	/**
	 * 分页查询 返回page对象
	 * @param hql
	 * @param page
	 * @param params
	 * @return
	 */
	public Pager findSqlByPager(String hql,String countHql,Pager page,Class clazz,Object... params){
	 SQLQuery query = getSession().createSQLQuery(hql);
      if (params != null) {
        for (int i = 0; i < params.length; i++) {
            query.setParameter(i, params[i]);
        }
      }
      query.setFirstResult(page.getCurrPage() *page.getPageSize() - page.getPageSize());
      query.setMaxResults(page.getPageSize());
      page.setList(query.addEntity(clazz).list());
      page.setCount(getTotalByCond(countHql,params));
      return page;
	}
	
	
	public int getTotalByCond(String hql,Object... params){
		Query query = getSession().createQuery(hql);
//		 SQLQuery query = getSession().createSQLQuery(hql);

		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		int total = Integer.parseInt(query.list().get(0).toString());
		return total;
	}

	public void flush(){
		this.getSession().flush();
	}
	/**
	 * 根据hql删除
	 * chenchuan
	 * @param hql
	 * @param params
	 * @return 删除的记录数
	 */
	public int deleteByHql(String hql, Object[] params){
		Query query = getSession().createQuery(hql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		return query.executeUpdate();
	}
	
	/**
	 * 根据hql更新
	 * chenchuan
	 * @param hql
	 * @param params
	 * @return 删除的记录数
	 */
	public int updateByHql(String hql, Object[] params){
		Query query = getSession().createQuery(hql);
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		return query.executeUpdate();
	}
	
	/**
	 * 批量删除
	 * @param clazz
	 * @param fileName
	 * @param params
	 */
	public <T> void delBatch(Class<T> clazz,String fileName,Object[] params){
		StringBuffer hql = new StringBuffer("delete "+ clazz.getName() +" where "+ fileName + " in (");
		StringBuffer par = new StringBuffer();
		for(int i=0;i<params.length;i++){
			String p = params[i].toString();
			if(i==0){
				par.append("'"+p+"'");
			}else{
				par.append(",'"+p+"'");
			}
		}
		hql.append(par.toString() + ")");
		Query query = getSession().createQuery(hql.toString());
		query.executeUpdate();
	}
	
	/**
	 * 排序
	 * 
	 * @author chenchuan
	 * 2014年10月23日
	 */
	public String addSort(StringBuffer buf,Pager pager){
		if(pager == null)
			return buf.toString();
		String filed = pager.getSortname();
		String order = pager.getSortorder();
		buf.append(" order by "+filed);
		buf.append(" "+order);
		return buf.toString();
	}
	
	/**
	 * 数据过滤
	 * @param Filter
	 * @return
	 */
	public <T> String getFilterSql (Map<String, List<String>> filter ){
		StringBuffer filterSql = new StringBuffer("");;
//		if(!filter.isEmpty())
//			return filterSql.toString();
//		Set<String> keySet = filter.keySet();
//		Iterator iter = keySet.iterator();
//		while(iter.hasNext()){
//			String filed = iter.next().toString();
//			List<String> list = filter.get(filed);
//			if(list != null && list.size() > 0){
//				filterSql.append("and "+ filed + " in ( ");
//				for(int i=0;i<list.size();i++){
//					if(i==0){
//						filterSql.append("'"+p+"'");
//					}else{
//						filterSql.append(",'"+p+"'");
//					}
//				}
//				filterSql.append(" )");
//			}
//		}
		return filterSql.toString();
	}

	@Override
	public <T> List<T> findByParams(Class<T> clazz, String fileName,
			Object[] params) {
		
		StringBuffer hql = new StringBuffer("from "+ clazz.getName() +" where "+ fileName + " in (");
		StringBuffer par = new StringBuffer();
		for(int i=0;i<params.length;i++){
			String p = params[i].toString();
			if(i==0){
				par.append("'"+p+"'");
			}else{
				par.append(",'"+p+"'");
			}
		}
		hql.append(par.toString() + ")");
		Query query = getSession().createQuery(hql.toString());
		List<T> list = query.list();
		
		return list;
	}
	
	@Override
	public <T> BaseObject submit(Class<T> clazz, Object[] uuids) {
		String date = DateUtils.parseDate("yyyy-MM-dd", new Date());
		SysUser user = (SysUser)SessionUtil.getAttribute("user");
		StringBuffer hql = new StringBuffer("update "+clazz.getName()+" set ");
		hql.append(" alterUser=?,alterDate=?,");
		hql.append(" status=?");
		hql.append(" where uuid in ( ");
		StringBuffer par = new StringBuffer();
		for(int i=0;i<uuids.length;i++){
			String p = uuids[i].toString();
			if(i==0){
				par.append("'"+p+"'");
			}else{
				par.append(",'"+p+"'");
			}
		}
		hql.append(par.toString() + ")");
		Query query = getSession().createQuery(hql.toString());
		query.setParameter(0, user.getUuid());
		query.setParameter(1, date);
		query.setParameter(2, Constants.SUBMITTATUS);
		int count = query.executeUpdate();
		BaseObject obj = new BaseObject();
		obj.setAlterDate(date);
		obj.setAlterUser(user);
		obj.setStatus(Constants.SUBMITTATUS);
		return obj;
	}
	

	@Override
	public <T> BaseObject audit(Class<T> clazz, Object[] uuids) {
		String date = DateUtils.parseDate("yyyy-MM-dd", new Date());
		SysUser user = (SysUser)SessionUtil.getAttribute("user");
		StringBuffer hql = new StringBuffer("update "+clazz.getName()+" set auditUser=?, auditDate=?");
		hql.append(" alterUser=?,alterDate=?");
		hql.append(" status=?");
		hql.append(" where uuid in ( ");
		StringBuffer par = new StringBuffer();
		for(int i=0;i<uuids.length;i++){
			String p = uuids[i].toString();
			if(i==0){
				par.append("'"+p+"'");
			}else{
				par.append(",'"+p+"'");
			}
		}
		hql.append(par.toString() + ")");
		Query query = getSession().createQuery(hql.toString());
		query.setParameter(0, user.getUuid());
		query.setParameter(1, date);
		query.setParameter(2, user.getUuid());
		query.setParameter(3, date);
		query.setParameter(4, Constants.AUDITSTATUS);
		int count = query.executeUpdate();
		
		BaseObject obj = new BaseObject();
		obj.setAlterDate(date);
		obj.setAlterUser(user);
		obj.setAuditDate(date);
		obj.setAuditUser(user);
		obj.setStatus(Constants.AUDITSTATUS);
		return obj;
	}

	@Override
	public <T> BaseObject unAudit(Class<T> clazz, Object[] uuids) {
		String date = DateUtils.parseDate("yyyy-MM-dd", new Date());
		SysUser user = (SysUser)SessionUtil.getAttribute("user");
		StringBuffer hql = new StringBuffer("update "+clazz.getName()+" set auditUser=?, auditDate=?");
		hql.append(" alterUser=?,alterDate=?");
		hql.append(" status=?");
		hql.append(" where uuid in ( ");
		StringBuffer par = new StringBuffer();
		for(int i=0;i<uuids.length;i++){
			String p = uuids[i].toString();
			if(i==0){
				par.append("'"+p+"'");
			}else{
				par.append(",'"+p+"'");
			}
		}
		hql.append(par.toString() + ")");
		Query query = getSession().createQuery(hql.toString());
		query.setParameter(0, user.getUuid());
		query.setParameter(1, date);
		query.setParameter(2, null);
		query.setParameter(3, null);
		query.setParameter(4, Constants.SAVESTATUS);
		int count = query.executeUpdate();
		
		BaseObject obj = new BaseObject();
		obj.setAlterDate(date);
		obj.setAlterUser(user);
		obj.setAuditDate(null);
		obj.setAuditUser(null);
		obj.setStatus(Constants.SAVESTATUS);
		return null;
	}

	@Override
	public <T> T findByUuid(Class<T> clazz,String uuid) {
		String hql = "from "+ clazz.getName() +" where uuid=?";
		Query query = getSession().createQuery(hql);
		query.setParameter(0, uuid);
		List<T> list = query.list();
		return list.get(0);
	}

	public Long countByHql(String hql){
      return (Long) getSession().createQuery(hql).uniqueResult();
	}
	
	
	public Object executeSql(String sql,Object[] parameters){
	  SQLQuery query = getSession().createSQLQuery(sql);
	  if(null!=parameters){
	    for(int i=0;i<parameters.length;i++){
	      query.setParameter(i,parameters[i]);
	    }
	  }
	  return query.list();
	}

  @Override
  public <T> List<T> findByHqlReNewObj(String hql, Object[] parameters, Class<T> Clazz) {
   /* String queryStr =
        "select NEW package.YourDefinedCustomClass(
         a.field1, b.field2, c.field3, c.field4) from a left outer join b 
         on a.id=b.fk left outer join c on b.id=c.fk";
*/
    
   /* TypedQuery<T> query =
        entityManager.createQuery(hql,Clazz);*/
    Query query = getSession().createQuery(hql);
    if(null!=parameters){
      for(int i=0;i<parameters.length;i++){
        query.setParameter(i,parameters[i]);
      }
    }
    List<T> results = query.list();
    return results;
  }
	
}